﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Windows;
using ButsaScraperLib;
using System.Windows.Threading;
using System.Threading;
using System.Xml;
using Microsoft.Win32;

namespace ForeCaster
{
	/// <summary>
	/// Interaction logic for MainWindow.xaml
	/// </summary>
	public partial class MainWindow
	{
		private List<ForecastPair> _forecastPairs;

		public MainWindow()
		{
			InitializeComponent();
			Closed += MainWindow_Closed;
		}

		void MainWindow_Closed(object sender, EventArgs e)
		{
			TeamIdByNameCache.Instance.Dispose();
			TeamIdByCodeCache.Instance.Dispose();
		}

		private void LoadFromWebButtonClick(object sender, RoutedEventArgs e)
		{
			if (_forecastPairs != null)
				_forecastPairs.Clear();
			Thread thread =
				new Thread(
					delegate() { _forecastPairs = ButsaManager.Instance.ReadForecastTable(ProgressLoadForecastTableCallback); })
					{IsBackground = true};
			thread.Start();
			LoadFromWebButton.IsEnabled = false;
			SaveForecastButton.IsEnabled = false;
		}

		private void ProgressLoadForecastTableCallback(object sender, ProgressEventArgs args)
		{
			Dispatcher.BeginInvoke(DispatcherPriority.Input, (ThreadStart)delegate 
			{ 
				LoadFromWebProgressControl.Value = args.CurrentProgress;
				LoadFromWebProgressLabel.Content = args.InfoMessage;
				if (Math.Abs(args.CurrentProgress - 100) < EPSILON)
				{
					SaveForecastButton.IsEnabled = true;
					LoadFromWebButton.IsEnabled = true;
					LoadFromWebProgressLabel.Content = "Завершено";
				}
			});
		}

		protected double EPSILON
		{
			get { return 0.000001; }
		}

		private void SaveForecastButtonClick(object sender, RoutedEventArgs e)
		{
			SaveFileDialog dlg = new SaveFileDialog { DefaultExt = ".bfxml", Filter = "Butsa forecast documents (.bfxml)|*.bfxml" };
			if (dlg.ShowDialog() == true)
			{
				string filename = dlg.FileName;
				XmlDocument forecastSnapshot = CreateXmlDocumentFromForecastPairs();
				if (File.Exists(filename) && forecastSnapshot.DocumentElement != null)
				{
					XmlTextReader xmlreader1 = new XmlTextReader(new StringReader(forecastSnapshot.DocumentElement.OuterXml));
					FileStream existedFileStream = new FileStream(filename, FileMode.Open, FileAccess.ReadWrite);
					XmlTextReader xmlreader2 = new XmlTextReader(existedFileStream);

					DataSet ds = new DataSet();
					ds.ReadXml(xmlreader1);
					DataSet ds2 = new DataSet();
					ds2.ReadXml(xmlreader2);
					ds.Merge(ds2);
					existedFileStream.Close();
					existedFileStream.Dispose();
					ds.WriteXml(filename);
				}
				else
				{
					DataSet ds = new DataSet();
					ds.ReadXml(new StringReader(forecastSnapshot.InnerXml));
					ds.WriteXml(filename);
				}
				MessageBox.Show("Сохранено.");
			}
		}

		private XmlDocument CreateXmlDocumentFromForecastPairs()
		{
			XmlDocument xmlDocument = new XmlDocument();
			var snapshot = xmlDocument.CreateElement("snapsot");
			var completedAttribute = xmlDocument.CreateAttribute("completed");
			var shotDateAttribute = xmlDocument.CreateAttribute("shotDate");
			completedAttribute.Value = "0";
			shotDateAttribute.Value = DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss");
			snapshot.Attributes.Append(completedAttribute);
			snapshot.Attributes.Append(shotDateAttribute);

			foreach (var forecastPair in _forecastPairs)
			{
				var pairNode = xmlDocument.CreateElement("pair");

				var homeTeamId = xmlDocument.CreateElement("HTeamId");
				var homeTeamName = xmlDocument.CreateElement("HTeamName");
				var homeTeamRating = xmlDocument.CreateElement("HRating");
				var homeTeamMaxGk = xmlDocument.CreateElement("HMaxGk");
				var homeTeamDefendP75I = xmlDocument.CreateElement("HDefendP75I");
				var homeTeamMiddleP75I = xmlDocument.CreateElement("HMiddleP75I");
				var homeTeamForwardP75I = xmlDocument.CreateElement("HForwardP75I");
				var homeTeamHasManager = xmlDocument.CreateElement("HHasManager");
				var guestTeamId = xmlDocument.CreateElement("GTeamId");
				var guestTeamName = xmlDocument.CreateElement("GTeamName");
				var guestTeamRating = xmlDocument.CreateElement("GRating");
				var guestTeamMaxGk = xmlDocument.CreateElement("GMaxGk");
				var guestTeamDefendP75I = xmlDocument.CreateElement("GDefendP75I");
				var guestTeamMiddleP75I = xmlDocument.CreateElement("GMiddleP75I");
				var guestTeamForwardP75I = xmlDocument.CreateElement("GForwardP75I");
				var guestTeamHasManager = xmlDocument.CreateElement("GHasManager");
				var homeTeamGoals = xmlDocument.CreateElement("HG");
				var guestTeamGoals = xmlDocument.CreateElement("GG");

				homeTeamId.InnerText = forecastPair.HomeTeam.TeamId;
				homeTeamName.InnerText = forecastPair.HomeTeam.TeamName;
				homeTeamRating.InnerText = forecastPair.HomeTeam.Rating.ToString(CultureInfo.InvariantCulture);
				homeTeamMaxGk.InnerText = MaxGk(forecastPair.HomeTeam).ToString(CultureInfo.InvariantCulture);
				homeTeamDefendP75I.InnerText = Percentel75IncForDefenders(forecastPair.HomeTeam).ToString(CultureInfo.InvariantCulture);
				homeTeamMiddleP75I.InnerText = Percentel75IncForMiddle(forecastPair.HomeTeam).ToString(CultureInfo.InvariantCulture);
				homeTeamForwardP75I.InnerText = Percentel75IncForForward(forecastPair.HomeTeam).ToString(CultureInfo.InvariantCulture);
				homeTeamHasManager.InnerText = forecastPair.HomeTeam.HasManager ? "1" : "0";

				guestTeamId.InnerText = forecastPair.GuestTeam.TeamId;
				guestTeamName.InnerText = forecastPair.GuestTeam.TeamName;
				guestTeamRating.InnerText = forecastPair.GuestTeam.Rating.ToString(CultureInfo.InvariantCulture);
				guestTeamMaxGk.InnerText = MaxGk(forecastPair.GuestTeam).ToString(CultureInfo.InvariantCulture);
				guestTeamDefendP75I.InnerText = Percentel75IncForDefenders(forecastPair.GuestTeam).ToString(CultureInfo.InvariantCulture);
				guestTeamMiddleP75I.InnerText = Percentel75IncForMiddle(forecastPair.GuestTeam).ToString(CultureInfo.InvariantCulture);
				guestTeamForwardP75I.InnerText = Percentel75IncForForward(forecastPair.GuestTeam).ToString(CultureInfo.InvariantCulture);
				guestTeamHasManager.InnerText = forecastPair.GuestTeam.HasManager ? "1" : "0";

				pairNode.AppendChild(homeTeamId);
				pairNode.AppendChild(homeTeamName);
				pairNode.AppendChild(homeTeamRating);
				pairNode.AppendChild(homeTeamMaxGk);
				pairNode.AppendChild(homeTeamDefendP75I);
				pairNode.AppendChild(homeTeamMiddleP75I);
				pairNode.AppendChild(homeTeamForwardP75I);
				pairNode.AppendChild(homeTeamHasManager);
				pairNode.AppendChild(guestTeamId);
				pairNode.AppendChild(guestTeamName);
				pairNode.AppendChild(guestTeamRating);
				pairNode.AppendChild(guestTeamMaxGk);
				pairNode.AppendChild(guestTeamDefendP75I);
				pairNode.AppendChild(guestTeamMiddleP75I);
				pairNode.AppendChild(guestTeamForwardP75I);
				pairNode.AppendChild(guestTeamHasManager);
				pairNode.AppendChild(homeTeamGoals);
				pairNode.AppendChild(guestTeamGoals);

				snapshot.AppendChild(pairNode);
			}

			xmlDocument.AppendChild(snapshot);
			return xmlDocument;
		}

		private double MaxGk(Team team)
		{
			return team.Players.Where(item => item.PrimaryPosition == Position.Gk)
				.Max(item => item.CalculatedTotalSkill);
		}

		private double Percentel75IncForDefenders(Team team)
		{
			var skills = team.Players
				.Where(item => item.PrimaryPosition == Position.Cd || item.PrimaryPosition == Position.Ld || item.PrimaryPosition == Position.Rd
					|| item.SecondaryPosition == Position.Cd || item.SecondaryPosition == Position.Ld || item.SecondaryPosition == Position.Rd)
				.Distinct()
				.Select(item => item.CalculatedTotalSkill)
				.ToArray();
			return Percentel75Inc(skills);
		}

		private double Percentel75IncForMiddle(Team team)
		{
			var skills = team.Players
				.Where(item => item.PrimaryPosition == Position.Cm || item.PrimaryPosition == Position.Lm || item.PrimaryPosition == Position.Rm
					|| item.SecondaryPosition == Position.Cm || item.SecondaryPosition == Position.Lm || item.SecondaryPosition == Position.Rm)
				.Distinct()
				.Select(item => item.CalculatedTotalSkill)
				.ToArray();
			return Percentel75Inc(skills);
		}

		private double Percentel75IncForForward(Team team)
		{
			var skills = team.Players
				.Where(item => item.PrimaryPosition == Position.Cf || item.PrimaryPosition == Position.Lf || item.PrimaryPosition == Position.Rf
					|| item.SecondaryPosition == Position.Cf || item.SecondaryPosition == Position.Lf || item.SecondaryPosition == Position.Rf)
				.Distinct()
				.Select(item => item.CalculatedTotalSkill)
				.ToArray();
			return Percentel75Inc(skills);
		}

		private double Percentel75Inc(double[] values)
		{
			int startIndex = (int)(values.Length*0.75) - 1;
			Array.Sort(values);
			double percentel = 0;
			for (int i = startIndex; i < values.Length; i++)
			{
				percentel += values[i];
			}
			percentel /= (values.Length - startIndex);
			return percentel;
		}


		private XmlDocument _forecastWithResults = null;
		private string _filename;
		private void OpenForecastsAndUploadResultsClick(object sender, RoutedEventArgs args)
		{
			OpenFileDialog dlg = new OpenFileDialog { DefaultExt = ".bfxml", Filter = "Butsa forecast documents (.bfxml)|*.bfxml" };
			if (dlg.ShowDialog() == true)
			{
				_filename = dlg.FileName;
				if (File.Exists(_filename))
				{
					FileStream existedFileStream = new FileStream(_filename, FileMode.Open, FileAccess.ReadWrite);
					XmlTextReader xmlReader = new XmlTextReader(existedFileStream);
					_forecastWithResults = new XmlDocument();
					_forecastWithResults.Load(xmlReader);
					if (_forecastWithResults.DocumentElement == null)
					{
						MessageBox.Show("Ничего не получится.");
						return;
					}
					if (_forecastWithResults.DocumentElement.Attributes["completed"].Value == "1")
					{
						MessageBox.Show("Прогноз уже закрыт.");
						return;
					}

					foreach (XmlNode node in _forecastWithResults.DocumentElement.ChildNodes)
					{
						string homeTeamId = node.ChildNodes.OfType<XmlNode>().First(item => item.Name == "HTeamId").InnerText;
						string homeTeamName = node.ChildNodes.OfType<XmlNode>().First(item => item.Name == "HTeamName").InnerText;
						string guestTeamId = node.ChildNodes.OfType<XmlNode>().First(item => item.Name == "GTeamId").InnerText;
						string guestTeamName = node.ChildNodes.OfType<XmlNode>().First(item => item.Name == "GTeamName").InnerText;

						Score score = ButsaManager.Instance.GetMatchResultForTeams(homeTeamId, guestTeamId);

						ForeCastText.Text += String.Format(String.Format("{0} ({1}) - {2} - {3} ({4})\r\n", homeTeamName, homeTeamId, score, guestTeamName, guestTeamId));

						node.ChildNodes.OfType<XmlNode>().First(item => item.Name == "HG").InnerText = score.HomeTeamGoals.ToString();
						node.ChildNodes.OfType<XmlNode>().First(item => item.Name == "GG").InnerText = score.GuestTeamGoals.ToString();
					}
					existedFileStream.Dispose();
				}
			}
		}

		private void SaveForecastResultsButtonClick(object sender, RoutedEventArgs args)
		{
			if (_forecastWithResults != null)
			{
				DataSet ds = new DataSet();
				ds.ReadXml(new StringReader(_forecastWithResults.InnerXml));
				ds.WriteXml(_filename);
			}
		}

	}
}
